using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml.Linq;
using System.Linq;

// 命名空间：图片名称转换工具相关功能
namespace 图名称转换
{
    /// <summary>
    /// 主窗体类：包含图片名称转换、XML处理、版本号管理等核心功能
    /// </summary>
    public partial class MainForm : Form
    {
        #region 私有字段

        /// <summary>
        /// 选中的根目录路径（需包含watchface和res文件夹）
        /// </summary>
        private string _selectedRootPath;

        /// <summary>
        /// 图片文件名映射字典：key=原始文件名，value=新文件名（时间戳命名）
        /// </summary>
        private Dictionary<string, string> _imageMappings;

        /// <summary>
        /// 图片文件名反向映射字典：key=新文件名，value=原始文件名（用于恢复操作）
        /// </summary>
        private Dictionary<string, string> _reverseMappings;

        /// <summary>
        /// XML配置文件备份路径（watch_face_config.xml的备份）
        /// </summary>
        private string _backupXmlPath;

        #endregion 私有字段

        #region 构造函数

        /// <summary>
        /// 主窗体构造函数：初始化控件和初始状态
        /// </summary>
        public MainForm()
        {
            // 初始化设计器生成的控件（包括版本号相关控件）
            InitializeComponent();

            // 初始化图片映射字典
            _imageMappings = new Dictionary<string, string>();
            _reverseMappings = new Dictionary<string, string>();

            // 初始状态设置：禁用未就绪的功能按钮
            btnGenerate.Enabled = false;    // 生成按钮（未选目录时禁用）
            btnDelete.Enabled = false;      // 恢复原始按钮（未生成时禁用）
            btnClearLog.Enabled = false;    // 清除日志按钮（无日志时禁用）

            // 版本号控件初始状态配置
            txtVersion.ReadOnly = true;                     // 初始只读（防止误编辑）
            txtVersion.PlaceholderText = "版本号将在此显示"; // 提示文本
            btnModifyVersion.Text = "修改版本号";            // 按钮文本
            btnModifyVersion.Enabled = false;               // 未选目录时禁用
        }

        #endregion 构造函数

        #region 根目录选择相关

        /// <summary>
        /// 浏览按钮点击事件：打开文件夹选择对话框，选择根目录
        /// </summary>
        private void btnBrowse_Click(object sender, EventArgs e)
        {
            // 文件夹选择对话框：让用户选择根目录
            using (var folderDialog = new FolderBrowserDialog())
            {
                folderDialog.Description = "请选择包含watchface和res文件夹的根目录";

                // 若用户选择了目录并确认
                if (folderDialog.ShowDialog() == DialogResult.OK)
                {
                    // 记录选中的根目录路径
                    _selectedRootPath = folderDialog.SelectedPath;
                    // 在文本框中显示选中的路径
                    txtRootFolder.Text = _selectedRootPath;

                    // 重置处理状态（清空映射、禁用恢复按钮等）
                    ResetProcessingState();

                    // 验证根目录结构是否符合要求（需包含watchface、res、配置文件）
                    var dirCheckResult = CheckDirectoryStructure(_selectedRootPath);
                    if (dirCheckResult == null)
                    {
                        // 目录有效：启用生成按钮、加载版本号
                        btnGenerate.Enabled = true;
                        AddLog("目录结构验证通过，可以生成");
                        btnClearLog.Enabled = true;
                        // 从description.xml加载版本号并显示
                        LoadVersionFromDescriptionXml(_selectedRootPath);
                    }
                    else
                    {
                        // 目录无效：禁用生成按钮、清空版本号
                        btnGenerate.Enabled = false;
                        AddLog($"目录结构无效：{dirCheckResult}");
                        btnClearLog.Enabled = true;
                        txtVersion.Text = "";
                        btnModifyVersion.Enabled = false;
                    }
                }
            }
        }

        /// <summary>
        /// 检查根目录结构是否符合要求
        /// </summary>
        /// <param name="rootPath">根目录路径</param>
        /// <returns>null=结构有效，否则返回错误信息</returns>
        private string CheckDirectoryStructure(string rootPath)
        {
            // 检查是否存在watchface文件夹
            string watchFaceFolder = Path.Combine(rootPath, "watchface");
            if (!Directory.Exists(watchFaceFolder)) return "缺少watchface文件夹";

            // 检查watchface文件夹下是否存在配置文件
            string configFile = Path.Combine(watchFaceFolder, "watch_face_config.xml");
            if (!File.Exists(configFile)) return "缺少watch_face_config.xml";

            // 检查watchface文件夹下是否存在res文件夹（存放图片）
            string resFolder = Path.Combine(watchFaceFolder, "res");
            if (!Directory.Exists(resFolder)) return "缺少res文件夹";

            // 所有检查通过
            return null;
        }

        #endregion 根目录选择相关

        #region 图片转换核心功能（生成按钮相关）

        /// <summary>
        /// 生成按钮点击事件：执行图片重命名、XML更新等核心逻辑
        /// </summary>
        private void btnGenerate_Click(object sender, EventArgs e)
        {
            // 未选择根目录时，提示用户先选择
            if (string.IsNullOrEmpty(_selectedRootPath))
            {
                MessageBox.Show("请先选择根目录", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // 清空历史日志和映射数据，启用清除日志按钮
            lstLog.Items.Clear();
            ResetProcessingState();
            btnClearLog.Enabled = true;

            try
            {
                // 1. 定义核心文件/文件夹路径
                string watchFaceFolder = Path.Combine(_selectedRootPath, "watchface");
                string configFilePath = Path.Combine(watchFaceFolder, "watch_face_config.xml"); // 主配置XML
                string resFolder = Path.Combine(watchFaceFolder, "res"); // 图片存放目录
                _backupXmlPath = Path.Combine(watchFaceFolder, "watch_face_config_backup.xml"); // 配置备份路径

                // 2. 备份原始XML配置文件（防止处理失败无法恢复）
                if (File.Exists(_backupXmlPath))
                {
                    File.Delete(_backupXmlPath); // 删除旧备份
                }
                File.Copy(configFilePath, _backupXmlPath); // 创建新备份
                AddLog("已创建XML配置文件备份");

                // 3. 加载XML并预处理（替换属性：res_name→res_active，res_left→res_active_left）
                XDocument doc = XDocument.Load(configFilePath);
                PreprocessXmlAttributes(doc);
                AddLog("XML预处理完成：res_name→res_active，res_left→res_active_left");

                // 4. 修改container的data_type（value_type=99的layer对应的container，将data_type=41改为1）
                UpdateContainerDataType(doc);
                AddLog("container.data_type处理完成");

                // 5. 复制date.element下的layer到widget.element（每个layer单独用container包裹，并删除原layer）
                CopyDateLayerToWidget(doc);
                AddLog("date.layer复制到widget.container（单独包裹）并删除原layer完成");

                // 6. 收集所有需要处理的图片引用（从element、container、layer中提取）
                // 6.1 提取带res_preview属性的element
                var elementWithPreview = doc.Descendants("element")
                                           .Where(el => el.Attribute("res_preview") != null)
                                           .ToList();
                // 6.2 提取带res_preview属性的container
                var containerWithPreview = doc.Descendants("container")
                                             .Where(con => con.Attribute("res_preview") != null)
                                             .ToList();
                // 6.3 提取带res_active或res_active_left属性的layer
                var layerWithImages = doc.Descendants("layer")
                                        .Where(lay => lay.Attribute("res_active") != null
                                                   || lay.Attribute("res_active_left") != null)
                                        .ToList();

                // 7. 收集所有图片文件名（去重）
                var allImageNames = new List<string>();
                // 7.1 收集element的res_preview值
                foreach (var element in elementWithPreview)
                {
                    string previewValue = element.Attribute("res_preview").Value.Trim();
                    if (!string.IsNullOrEmpty(previewValue))
                    {
                        AddLog($"从element.res_preview提取：{previewValue}");
                        allImageNames.Add(previewValue);
                    }
                }
                // 7.2 收集container的res_preview值
                foreach (var container in containerWithPreview)
                {
                    string previewValue = container.Attribute("res_preview").Value.Trim();
                    if (!string.IsNullOrEmpty(previewValue))
                    {
                        AddLog($"从container.res_preview提取：{previewValue}");
                        allImageNames.Add(previewValue);
                    }
                }
                // 7.3 收集layer的res_active（多图）和res_active_left（单图）值
                foreach (var layer in layerWithImages)
                {
                    // 处理res_active（逗号分隔的多图片）
                    if (layer.Attribute("res_active") != null)
                    {
                        string activeValue = layer.Attribute("res_active").Value.Trim();
                        if (!string.IsNullOrEmpty(activeValue))
                        {
                            // 分割、去重、提取图片名
                            string[] activeImages = activeValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                                              .Select(img => img.Trim())
                                                              .Distinct()
                                                              .ToArray();
                            allImageNames.AddRange(activeImages);
                            AddLog($"从layer.res_active提取：{string.Join(",", activeImages)}");
                        }
                    }
                    // 处理res_active_left（单图片）
                    if (layer.Attribute("res_active_left") != null)
                    {
                        string leftValue = layer.Attribute("res_active_left").Value.Trim();
                        if (!string.IsNullOrEmpty(leftValue))
                        {
                            AddLog($"从layer.res_active_left提取：{leftValue}");
                            allImageNames.Add(leftValue);
                        }
                    }
                }

                // 8. 全局去重，得到唯一图片列表
                var uniqueImages = allImageNames.Distinct().ToList();
                AddLog($"共找到 {uniqueImages.Count} 个唯一图片（含res_preview、res_active、res_active_left）");

                // 9. 生成图片文件名映射（原始文件名→时间戳新文件名）
                long baseTimestamp = Get13DigitTimestamp(); // 获取13位时间戳（作为新文件名基础）
                foreach (var imageName in uniqueImages)
                {
                    // 检查图片是否存在于res文件夹
                    string imagePath = Path.Combine(resFolder, imageName);
                    if (!File.Exists(imagePath))
                    {
                        AddLog($"警告：图片不存在 - {imageName}（跳过）");
                        continue;
                    }

                    // 生成新文件名（时间戳+原后缀）
                    string extension = Path.GetExtension(imageName);
                    string newFileName = $"{baseTimestamp}{extension}";
                    // 避免重复添加映射
                    if (!_imageMappings.ContainsKey(imageName))
                    {
                        _imageMappings[imageName] = newFileName;
                        _reverseMappings[newFileName] = imageName; // 反向映射（用于恢复）
                        AddLog($"映射生成：{imageName} → {newFileName}");
                        baseTimestamp++; // 时间戳递增，确保新文件名唯一
                    }
                }

                // 10. 执行图片重命名（按映射关系修改文件名）
                foreach (var mapping in _imageMappings)
                {
                    string oldPath = Path.Combine(resFolder, mapping.Key); // 原始图片路径
                    string newPath = Path.Combine(resFolder, mapping.Value); // 新图片路径

                    // 处理新文件名冲突（若新路径已存在，递增时间戳重新生成）
                    while (File.Exists(newPath))
                    {
                        string extension = Path.GetExtension(newPath);
                        baseTimestamp++;
                        newPath = Path.Combine(resFolder, $"{baseTimestamp}{extension}");
                        // 更新映射（替换旧的新文件名）
                        _reverseMappings.Remove(mapping.Value);
                        _imageMappings[mapping.Key] = Path.GetFileName(newPath);
                        _reverseMappings[Path.GetFileName(newPath)] = mapping.Key;
                        AddLog($"文件名冲突，更新映射：{mapping.Key} → {Path.GetFileName(newPath)}");
                    }

                    // 执行重命名
                    if (File.Exists(oldPath))
                    {
                        File.Move(oldPath, newPath);
                        AddLog($"文件重命名：{mapping.Key} → {Path.GetFileName(newPath)}");
                    }
                }

                // 11. 更新XML中的图片引用（将原始文件名替换为新文件名）
                // 11.1 更新element的res_preview
                foreach (var element in elementWithPreview)
                {
                    var previewAttr = element.Attribute("res_preview");
                    string oldValue = previewAttr.Value.Trim();
                    if (!string.IsNullOrEmpty(oldValue) && _imageMappings.ContainsKey(oldValue))
                    {
                        previewAttr.Value = _imageMappings[oldValue];
                        AddLog($"更新element.res_preview：{oldValue} → {previewAttr.Value}");
                    }
                }
                // 11.2 更新container的res_preview
                foreach (var container in containerWithPreview)
                {
                    var previewAttr = container.Attribute("res_preview");
                    string oldValue = previewAttr.Value.Trim();
                    if (!string.IsNullOrEmpty(oldValue) && _imageMappings.ContainsKey(oldValue))
                    {
                        previewAttr.Value = _imageMappings[oldValue];
                        AddLog($"更新container.res_preview：{oldValue} → {previewAttr.Value}");
                    }
                }
                // 11.3 更新layer的res_active和res_active_left
                foreach (var layer in layerWithImages)
                {
                    // 判断是否需要去重（特定value_type的layer需要去重图片）
                    XAttribute valueTypeAttr = layer.Attribute("value_type");
                    bool needDeduplicate = valueTypeAttr != null &&
                                          (valueTypeAttr.Value == "52" ||
                                           valueTypeAttr.Value == "92" ||
                                           valueTypeAttr.Value == "51");

                    // 更新res_active（支持去重）
                    var activeAttr = layer.Attribute("res_active");
                    if (activeAttr != null)
                    {
                        UpdateLayerImageAttr(activeAttr, needDeduplicate);
                    }

                    // 更新res_active_left（无需去重）
                    var leftAttr = layer.Attribute("res_active_left");
                    if (leftAttr != null)
                    {
                        UpdateLayerImageAttr(leftAttr, false);
                    }
                }

                // 12. 保存更新后的XML配置文件
                doc.Save(configFilePath);
                AddLog("XML配置文件已更新");
                btnDelete.Enabled = true; // 启用恢复按钮（生成完成后可恢复）
                MessageBox.Show("处理完成", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                // 捕获异常并提示用户
                AddLog($"错误：{ex.Message}");
                MessageBox.Show($"处理出错：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 更新layer标签的图片属性（res_active/res_active_left）
        /// </summary>
        /// <param name="attr">要更新的属性（res_active或res_active_left）</param>
        /// <param name="needDeduplicate">是否需要去重图片</param>
        private void UpdateLayerImageAttr(XAttribute attr, bool needDeduplicate)
        {
            string attrValue = attr.Value.Trim();
            // 属性值为空时，直接设为空字符串
            if (string.IsNullOrEmpty(attrValue))
            {
                attr.Value = "";
                return;
            }

            // 分割属性值为图片列表（按逗号分割）
            IEnumerable<string> images = attrValue
                .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(img => img.Trim());

            // 按需求去重
            if (needDeduplicate)
            {
                images = images.Distinct();
            }

            // 替换为新文件名（根据映射关系）
            List<string> newImages = new List<string>();
            foreach (var img in images)
            {
                if (_imageMappings.TryGetValue(img, out string newName))
                {
                    newImages.Add(newName);
                }
                else
                {
                    newImages.Add(img); // 未找到映射时保留原文件名
                    AddLog($"警告：未找到映射 - {img}");
                }
            }

            // 重新拼接属性值并保存
            attr.Value = string.Join(",", newImages);
            AddLog($"更新{attr.Name}：{attrValue} → {attr.Value}");
        }

        #endregion 图片转换核心功能（生成按钮相关）

        #region 恢复原始功能（删除按钮相关）

        /// <summary>
        /// 恢复原始按钮点击事件：将图片和XML恢复到生成前的状态
        /// </summary>
        private void btnDelete_Click(object sender, EventArgs e)
        {
            // 未选择根目录或无映射数据时，提示无法恢复
            if (string.IsNullOrEmpty(_selectedRootPath) || _reverseMappings.Count == 0)
            {
                MessageBox.Show("没有可恢复的操作", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // 确认用户是否要执行恢复操作
            if (MessageBox.Show("确定恢复原始文件和配置吗？", "确认",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
            {
                return;
            }

            try
            {
                // 定义核心路径
                string watchFaceFolder = Path.Combine(_selectedRootPath, "watchface");
                string configFilePath = Path.Combine(watchFaceFolder, "watch_face_config.xml");
                string resFolder = Path.Combine(watchFaceFolder, "res");

                // 1. 恢复图片（按反向映射还原文件名）
                foreach (var mapping in _reverseMappings)
                {
                    string newPath = Path.Combine(resFolder, mapping.Key); // 生成后的图片路径
                    string oldPath = Path.Combine(resFolder, mapping.Value); // 原始图片路径

                    if (File.Exists(newPath))
                    {
                        if (File.Exists(oldPath)) File.Delete(oldPath); // 若原始路径已存在，先删除
                        File.Move(newPath, oldPath); // 还原文件名
                        AddLog($"恢复图片：{mapping.Key} → {mapping.Value}");
                    }
                }

                // 2. 恢复XML配置文件（用备份文件替换当前文件）
                if (File.Exists(_backupXmlPath))
                {
                    if (File.Exists(configFilePath)) File.Delete(configFilePath); // 删除修改后的XML
                    File.Move(_backupXmlPath, configFilePath); // 恢复备份的原始XML
                    AddLog("恢复原始XML配置文件");
                }

                // 3. 重置处理状态（清空映射、禁用恢复按钮）
                ResetProcessingState();
                btnDelete.Enabled = false;
                MessageBox.Show("已恢复原始文件和配置", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                // 捕获恢复过程中的异常
                AddLog($"恢复错误：{ex.Message}");
                MessageBox.Show($"恢复出错：{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion 恢复原始功能（删除按钮相关）

        #region 日志相关

        /// <summary>
        /// 清除日志按钮点击事件：清空日志列表
        /// </summary>
        private void btnClearLog_Click(object sender, EventArgs e)
        {
            // 日志已为空时，提示用户
            if (lstLog.Items.Count == 0)
            {
                MessageBox.Show("日志已为空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // 确认用户是否要清空日志
            if (MessageBox.Show("确定清空日志？", "确认",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                lstLog.Items.Clear();
                AddLog("日志已清空");
            }
        }

        /// <summary>
        /// 添加日志到日志列表（带时间戳，自动滚动到最新条目）
        /// </summary>
        /// <param name="message">日志内容</param>
        private void AddLog(string message)
        {
            // 日志格式：[HH:mm:ss] 内容
            lstLog.Items.Add($"[{DateTime.Now:HH:mm:ss}] {message}");
            // 自动滚动到最后一行（显示最新日志）
            lstLog.TopIndex = lstLog.Items.Count - 1;
        }

        #endregion 日志相关

        #region XML处理辅助方法

        /// <summary>
        /// XML预处理：替换属性（res_name→res_active，res_left→res_active_left）
        /// </summary>
        /// <param name="doc">要处理的XML文档</param>
        private void PreprocessXmlAttributes(XDocument doc)
        {
            // 获取所有layer标签
            var layers = doc.Descendants("layer").ToList();
            foreach (var layer in layers)
            {
                // 1. 处理res_name属性：替换为res_active
                var resNameAttr = layer.Attribute("res_name");
                if (resNameAttr != null)
                {
                    string value = resNameAttr.Value.Trim();
                    // 若res_active不存在，先创建
                    if (layer.Attribute("res_active") == null)
                    {
                        layer.Add(new XAttribute("res_active", ""));
                    }
                    // 将res_name的值赋值给res_active，然后删除res_name
                    var resActiveAttr = layer.Attribute("res_active");
                    resActiveAttr.Value = value;
                    resNameAttr.Remove();
                    AddLog($"替换res_name→res_active，值：{value}");
                }

                // 2. 处理res_left属性：替换为res_active_left
                var resLeftAttr = layer.Attribute("res_left");
                if (resLeftAttr != null)
                {
                    string value = resLeftAttr.Value.Trim();
                    // 若res_active_left不存在，先创建
                    if (layer.Attribute("res_active_left") == null)
                    {
                        layer.Add(new XAttribute("res_active_left", ""));
                    }
                    // 将res_left的值赋值给res_active_left，然后删除res_left
                    var resActiveLeftAttr = layer.Attribute("res_active_left");
                    resActiveLeftAttr.Value = value;
                    resLeftAttr.Remove();
                    AddLog($"替换res_left→res_active_left，值：{value}");
                }

                // 3. 仅含res_primary的layer执行额外操作
                var resPrimaryAttr = layer.Attribute("res_primary");
                if (resPrimaryAttr != null)
                {
                    // 3.1 删除空res_name（res_name=""，可能是转换后新增的空值）
                    var newResNameAttr = layer.Attribute("res_name"); // 此处res_name可能是之前转换生成的
                    if (newResNameAttr != null && string.IsNullOrEmpty(newResNameAttr.Value.Trim()))
                    {
                        newResNameAttr.Remove();
                        AddLog($"  已删除空res_name属性（因存在res_primary）");
                    }

                    // 3.2 删除defaut_preview_end（含拼写错误）
                    var defaultPreviewEndAttr = layer.Attribute("default_preview_end");
                    if (defaultPreviewEndAttr != null)
                    {
                        defaultPreviewEndAttr.Remove();
                        AddLog($"  已删除default_preview_end");
                    }
                    var misspelledAttr = layer.Attribute("defaut_preview_end");
                    if (misspelledAttr != null)
                    {
                        misspelledAttr.Remove();
                        AddLog($"  已删除defaut_preview_end（修正拼写）");
                    }

                    // 3.3 删除line_cap
                    var lineCapAttr = layer.Attribute("line_cap");
                    if (lineCapAttr != null)
                    {
                        lineCapAttr.Remove();
                        AddLog($"  已删除line_cap");
                    }

                    // 3.4 删除res_active（之前转换生成的）
                    var resActiveAttr = layer.Attribute("res_active");
                    if (resActiveAttr != null)
                    {
                        string removedValue = resActiveAttr.Value.Trim();
                        resActiveAttr.Remove();
                        AddLog($"  已删除res_active（原值：{removedValue}）");
                    }

                    // 3.5 删除res_secondary
                    var resSecondaryAttr = layer.Attribute("res_secondary");
                    if (resSecondaryAttr != null)
                    {
                        string removedValue = resSecondaryAttr.Value.Trim();
                        resSecondaryAttr.Remove();
                        AddLog($"  已删除res_secondary（原值：{removedValue}）");
                    }

                    // 3.6 res_primary→res_name
                    string primaryValue = resPrimaryAttr.Value.Trim();
                    if (layer.Attribute("res_name") != null)
                        layer.Attribute("res_name").Value = primaryValue;
                    else
                        layer.Add(new XAttribute("res_name", primaryValue));
                    resPrimaryAttr.Remove();
                    AddLog($"  已将res_primary→res_name（值：{primaryValue}）");

                    // 3.7 添加cap_type="square"
                    var capTypeAttr = layer.Attribute("cap_type");
                    if (capTypeAttr == null)
                    {
                        layer.Add(new XAttribute("cap_type", "square"));
                        AddLog($"  已添加cap_type=\"square\"");
                    }
                    else
                    {
                        AddLog($"  已存在cap_type（值：{capTypeAttr.Value}）");
                    }

                    AddLog($"  含res_primary的layer处理完成");
                }

                // 4. 处理res_active空值：确保显式为空字符串（避免XML属性值异常）
                var activeAttr = layer.Attribute("res_active");
                if (activeAttr != null)
                {
                    activeAttr.Value = activeAttr.Value.Trim();
                }
            }
        }

        /// <summary>
        /// 修改container的data_type：将value_type=99的layer对应的container的data_type=41改为1
        /// </summary>
        /// <param name="doc">要处理的XML文档</param>
        private void UpdateContainerDataType(XDocument doc)
        {
            // 找到所有value_type=99的layer（目标layer）
            var targetLayers = doc.Descendants("layer")
                          .Where(lay =>
                              lay.Attribute("value_type") != null
                              && lay.Attribute("value_type").Value.Trim() == "99")
                          .ToList();

            // 无目标layer时，直接返回
            if (!targetLayers.Any())
            {
                AddLog("未找到value_type=99的layer，无需修改container");
                return;
            }

            // 处理每个目标layer的父container
            foreach (var layer in targetLayers)
            {
                // 获取layer的直接父节点（需为container标签）
                var parentContainer = layer.Parent as XElement;
                if (parentContainer == null || parentContainer.Name != "container")
                {
                    AddLog($"警告：value_type=99的layer无有效父container（跳过）");
                    continue;
                }

                // 获取container的data_type属性
                var dataTypeAttr = parentContainer.Attribute("data_type");
                if (dataTypeAttr == null)
                {
                    AddLog($"警告：目标container无data_type属性（跳过）");
                    continue;
                }

                // 仅当data_type=41时，修改为1
                string currentDataType = dataTypeAttr.Value.Trim();
                if (currentDataType == "41")
                {
                    dataTypeAttr.Value = "1";
                    AddLog($"修改container.data_type：{currentDataType} → 1（父container索引：{parentContainer.Attribute("index")?.Value}）");
                }
                else
                {
                    AddLog($"目标container的data_type为{currentDataType}（非41，无需修改）");
                }
            }
        }

        /// <summary>
        /// 复制date.element下的layer到widget.element：
        /// 每个value_type=99的layer单独用container包裹，插入到widget.element，同时删除原layer
        /// </summary>
        /// <param name="doc">要处理的XML文档</param>
        private void CopyDateLayerToWidget(XDocument doc)
        {
            // 1. 找到label为date和widget的element（目标元素）
            var dateElement = doc.Descendants("element")
                         .FirstOrDefault(el => el.Attribute("label")?.Value.Trim() == "date");
            var widgetElement = doc.Descendants("element")
                          .FirstOrDefault(el => el.Attribute("label")?.Value.Trim() == "widget");

            // 缺少目标element时，提示并返回
            if (dateElement == null)
            {
                AddLog("警告：未找到label=\"date\"的element，跳过复制操作");
                return;
            }
            if (widgetElement == null)
            {
                AddLog("警告：未找到label=\"widget\"的element，跳过复制操作");
                return;
            }

            // 2. 获取date.element下所有value_type=99的layer（要复制的layer）
            var originalLayers = dateElement.Descendants("layer")
                                    .Where(lay => lay.Attribute("value_type") != null
                                                && lay.Attribute("value_type").Value.Trim() == "99")
                                    .ToList();

            // 无目标layer时，提示并返回
            if (!originalLayers.Any())
            {
                AddLog("未找到date.element下value_type=99的layer，跳过复制操作");
                return;
            }
            AddLog($"从date.element找到 {originalLayers.Count} 个value_type=99的layer，准备处理");

            // 3. 计算widget.element下现有container的最大index（用于生成新container的唯一index）
            int maxContainerIndex = widgetElement.Descendants("container")
                                         .Select(con =>
                                         {
                                             int index;
                                             // 尝试解析index值，失败则取0
                                             return int.TryParse(con.Attribute("index")?.Value.Trim(), out index) ? index : 0;
                                         })
                                         .DefaultIfEmpty(0)
                                         .Max();
            int currentNewIndex = maxContainerIndex + 1; // 新container的起始index（确保不重复）

            // 4. 为每个原始layer创建单独的container并复制到widget.element
            foreach (var originalLayer in originalLayers)
            {
                // 深复制layer（避免修改原始节点）
                var copiedLayer = new XElement(originalLayer);

                // 创建新container（配置固定属性）
                var newContainer = new XElement("container");
                newContainer.Add(new XAttribute("data_type", "1"));
                newContainer.Add(new XAttribute("is_support_option", "false"));
                newContainer.Add(new XAttribute("index", currentNewIndex));
                newContainer.Add(new XAttribute("res_preview", "")); // 空属性（与示例保持一致）
                newContainer.Add(new XAttribute("rect", "")); // 空属性（与示例保持一致）

                // 将复制的layer添加到新container
                newContainer.Add(copiedLayer);

                // 将新container添加到widget.element
                widgetElement.Add(newContainer);

                AddLog($"已创建新container（index={currentNewIndex}），包含复制的layer（原index={originalLayer.Attribute("index")?.Value}）");
                currentNewIndex++; // index递增，确保下一个container唯一
            }

            // 5. 删除date.element中原有的value_type=99的layer
            foreach (var layerToRemove in originalLayers)
            {
                string layerIndex = layerToRemove.Attribute("index")?.Value ?? "未知";
                layerToRemove.Remove();
                AddLog($"已删除date.element中value_type=99的layer（index={layerIndex}）");
            }
        }

        #endregion XML处理辅助方法

        #region 版本号管理相关

        /// <summary>
        /// 从description.xml加载版本号，并显示到txtVersion文本框
        /// </summary>
        /// <param name="rootPath">根目录路径（description.xml所在路径）</param>
        private void LoadVersionFromDescriptionXml(string rootPath)
        {
            string descriptionPath = Path.Combine(rootPath, "description.xml");
            // 检查description.xml是否存在
            if (!File.Exists(descriptionPath))
            {
                AddLog("警告：根目录下缺少description.xml，无法显示版本号");
                txtVersion.Text = "";
                btnModifyVersion.Enabled = false;
                return;
            }

            try
            {
                // 加载XML并获取version节点
                XDocument doc = XDocument.Load(descriptionPath);
                XElement versionElement = doc.Descendants("version").FirstOrDefault();
                if (versionElement == null)
                {
                    AddLog("警告：description.xml中缺少<version>节点");
                    txtVersion.Text = "";
                }
                else
                {
                    // 读取版本号并显示
                    string version = versionElement.Value.Trim();
                    txtVersion.Text = version;
                    AddLog($"已加载版本号：{version}（来自description.xml）");
                }
                btnModifyVersion.Enabled = true; // 加载成功后启用修改按钮
            }
            catch (Exception ex)
            {
                // 加载失败时提示并禁用按钮
                AddLog($"加载版本号失败：{ex.Message}");
                txtVersion.Text = "";
                btnModifyVersion.Enabled = false;
            }
        }

        /// <summary>
        /// 修改单个XML文件中的version节点值
        /// </summary>
        /// <param name="xmlPath">XML文件路径</param>
        /// <param name="newVersion">新版本号</param>
        /// <returns>修改结果信息（成功/失败描述）</returns>
        private string ModifyVersionInXml(string xmlPath, string newVersion)
        {
            // 检查XML文件是否存在
            if (!File.Exists(xmlPath))
            {
                return $"文件不存在：{Path.GetFileName(xmlPath)}";
            }

            try
            {
                // 加载XML并获取version节点
                XDocument doc = XDocument.Load(xmlPath);
                XElement versionElement = doc.Descendants("version").FirstOrDefault();
                if (versionElement == null)
                {
                    return $"{Path.GetFileName(xmlPath)}中缺少<version>节点";
                }

                // 替换版本号并保存
                string oldVersion = versionElement.Value.Trim();
                versionElement.Value = newVersion;
                doc.Save(xmlPath);
                return $"成功修改{Path.GetFileName(xmlPath)}：{oldVersion} → {newVersion}";
            }
            catch (Exception ex)
            {
                return $"修改{Path.GetFileName(xmlPath)}失败：{ex.Message}";
            }
        }

        /// <summary>
        /// 修改版本号按钮点击事件：切换文本框编辑状态，执行版本号修改
        /// </summary>
        private void btnModifyVersion_Click(object sender, EventArgs e)
        {
            // 未选择根目录时，提示用户
            if (string.IsNullOrEmpty(_selectedRootPath))
            {
                MessageBox.Show("请先选择根目录", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            // 切换文本框只读状态（编辑模式/提交模式）
            if (txtVersion.ReadOnly)
            {
                // 进入编辑模式：可输入新版本号
                txtVersion.ReadOnly = false;
                txtVersion.Focus(); // 聚焦到文本框，方便输入
                btnModifyVersion.Text = "确认修改"; // 按钮文本改为"确认修改"
                AddLog("文本框已可编辑，请输入新版本号");
            }
            else
            {
                // 进入提交模式：验证并修改版本号
                string newVersion = txtVersion.Text.Trim();
                // 版本号为空时，提示用户
                if (string.IsNullOrEmpty(newVersion))
                {
                    MessageBox.Show("版本号不能为空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    txtVersion.Focus();
                    return;
                }

                // 定义需要修改的两个XML文件路径
                string descriptionPath = Path.Combine(_selectedRootPath, "description.xml");
                string watchFaceInfoPath = Path.Combine(_selectedRootPath, "watchface", "watch_face_info.xml");

                // 执行修改并记录日志
                AddLog("开始修改版本号...");
                string result1 = ModifyVersionInXml(descriptionPath, newVersion);
                AddLog(result1);

                string result2 = ModifyVersionInXml(watchFaceInfoPath, newVersion);
                AddLog(result2);

                // 恢复只读状态
                txtVersion.ReadOnly = true;
                btnModifyVersion.Text = "修改版本号";
                MessageBox.Show("版本号修改完成，查看日志确认结果", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        #endregion 版本号管理相关

        #region 通用辅助方法

        /// <summary>
        /// 重置处理状态：清空映射、重置备份路径、禁用恢复按钮（保留版本号状态）
        /// </summary>
        private void ResetProcessingState()
        {
            // 清空图片映射字典
            _imageMappings.Clear();
            _reverseMappings.Clear();
            // 重置备份路径
            _backupXmlPath = "";
            // 禁用恢复原始按钮
            btnDelete.Enabled = false;
            // 注：不重置版本号控件（txtVersion和btnModifyVersion），确保生成后仍可修改版本号
        }

        /// <summary>
        /// 生成13位时间戳（UTC时间，单位：毫秒）
        /// </summary>
        /// <returns>13位时间戳（long类型）</returns>
        private long Get13DigitTimestamp()
        {
            // 计算从1970-01-01 00:00:00 UTC到当前UTC时间的毫秒数
            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }

        #endregion 通用辅助方法
    }
}